package tech.yqyl.halo;

import cn.hutool.core.text.StrFormatter;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Splitter;
import lombok.Data;
import tech.yqyl.StringUtil;
import tech.yqyl.YamlUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

@Data
public class ArticleStore extends HaloStore {

    private Map<String, ArticleEntity> cache = new HashMap<>();
    private TagStore tagStore = new TagStore();
    private CategoriesStore categoriesStore = new CategoriesStore();
    private String postUri = HaloMarkdownBoot.server.getDomain().concat("/apis/api.console.halo.run/v1alpha1/posts");
    private String putUri = HaloMarkdownBoot.server.getDomain().concat("/apis/content.halo.run/v1alpha1/posts/{}");
    private String contentUri = HaloMarkdownBoot.server.getDomain().concat("/apis/api.console.halo.run/v1alpha1/posts/{}/content");
    private String pageUri = HaloMarkdownBoot.server.getDomain().concat("/apis/api.console.halo.run/v1alpha1/posts?page={}&size={}&labelSelector=content.halo.run%2Fdeleted%3Dfalse&keyword=");
    private String publishUri = HaloMarkdownBoot.server.getDomain().concat("/apis/api.console.halo.run/v1alpha1/posts/{}/publish");
    private String postTemplate = "{\n" +
            "    \"post\": {\n" +
            "        \"spec\": {\n" +
            "            \"title\": \"{}\",\n" +
            "            \"slug\": \"{}\",\n" +
            "            \"template\": \"\",\n" +
            "            \"cover\": \"\",\n" +
            "            \"deleted\": false,\n" +
            "            \"publish\": false,\n" +
            "            \"pinned\": false,\n" +
            "            \"allowComment\": true,\n" +
            "            \"visible\": \"PUBLIC\",\n" +
            "            \"priority\": 0,\n" +
            "            \"excerpt\": {\n" +
            "                \"autoGenerate\": true,\n" +
            "                \"raw\": \"\"\n" +
            "            },\n" +
            "            \"categories\": [],\n" +
            "            \"tags\": [],\n" +
            "            \"htmlMetas\": []\n" +
            "        },\n" +
            "        \"apiVersion\": \"content.halo.run/v1alpha1\",\n" +
            "        \"kind\": \"Post\",\n" +
            "        \"metadata\": {\n" +
            "            \"name\": \"{}\",\n" +
            "            \"annotations\": {\n" +
            "                \"content.halo.run/preferred-editor\": \"stackedit\"\n" +
            "            }\n" +
            "        }\n" +
            "    },\n" +
            "    \"content\": {\n" +
            "        \"raw\": \"\",\n" +
            "        \"content\": \"\",\n" +
            "        \"rawType\": \"markdown\"\n" +
            "    }\n" +
            "}";

    private void create(ArticleEntity article) {
        String postData = StrFormatter.format(getPostTemplate(), article.getTitle(), article.getSlugId(), article.getMetadataName() );
        JSONObject postDataJson = JSONObject.parseObject(postData);
        if( !StringUtil.isEmpty(article.getTags()) ) {
            JSONArray tags = postDataJson.getJSONObject("post").getJSONObject("spec").getJSONArray("tags");
            Splitter.on(",").trimResults().omitEmptyStrings().splitToList(article.getTags())
                    .stream().forEach(tag->{
                                String metadataName = tagStore.create(tag);
                                if( tags!=null ) {
                                    tags.add(metadataName);
                                }
                        }
                    );
        }
        if( !StringUtil.isEmpty(article.getCategories()) ) {
            JSONArray cates = postDataJson.getJSONObject("post").getJSONObject("spec").getJSONArray("categories");
            Splitter.on(",").trimResults().omitEmptyStrings().splitToList(article.getCategories())
                    .stream().forEach(cate->{
                                String metadataName = categoriesStore.create(cate);
                                if( cates!=null ) {
                                    cates.add(metadataName);
                                }
                            }
                    );
        }
        String snapshotId = post(postUri, HaloMarkdownBoot.server, ()-> postDataJson.toJSONString(), rspData->{
            return JSONObject.parseObject(rspData).getJSONObject("spec").getString("baseSnapshot");
        });
        article.setSnapshotId(snapshotId);
    }

    private void put(ArticleEntity article){
        Content content = new Content();
        content.setSnapshotName(article.getSnapshotId());
        content.setRaw(article.getRawContent());
        content.setContent(article.getContent());
        content.setRawType("markdown");
        String putUri = StrFormatter.format(contentUri, article.getMetadataName());
        put(putUri, HaloMarkdownBoot.server, ()->JSONObject.toJSONString(content), rspData->{
            return rspData;
        });
    }

    /**
     * 创建 博客文章
     * @param article
     */
    public void createOrUpdate(ArticleEntity article) {
        if( cache.isEmpty() ) {
            page(0,0, article.getTitle());
        }
        if( !cache.containsKey(article.getTitle()) ) {
            create(article);
        } else {
            if(!YamlUtils.getConfig().getHalo().isUpdate()) {
                System.err.println("[warn] 当前发布不允许覆盖已存在文章!");
                return;
            }
            update(article);
        }
        put(article);
    }

    public void publish(String title) {
        if( cache.isEmpty() ) {
            page(0,0, title);
        }
        if( !cache.containsKey(title) ) {
            throw new RuntimeException(StrFormatter.format("未能找到文章名为: [{}]的博客文章，请检查文章是否已创建!", title));
        }else {
            ArticleEntity articleEntity = cache.get(title);
            JSONObject status = articleEntity.getAkd().getJSONObject("status");
            status.put("phase","PUBLISHED");
            String publishUri = StrFormatter.format(getPublishUri(), articleEntity.getAkd().getJSONObject("metadata").getString("name"));
            // 更新 发布状态
            put(publishUri, HaloMarkdownBoot.server, ()-> articleEntity.getAkd().toJSONString(), rspData->{
                return rspData;
            });
        }
    }

    public void update(ArticleEntity article) {
        // 更新信息
        if( !StringUtil.isEmpty(article.getTags()) || !StringUtil.isEmpty(article.getCategories()) ) {
            page(0,0, article.getTitle());
            if( cache.containsKey(article.getTitle()) ) {
                ArticleEntity entity = cache.get(article.getTitle());
                if( !StringUtil.isEmpty(article.getTags()) ) {
                    Splitter.on(",").trimResults().omitEmptyStrings().splitToList(article.getTags())
                        .stream().forEach(tag->{
                            tagStore.create(tag);
                        }
                    );
                    JSONArray tag = entity.getAkd().getJSONObject("spec").getJSONArray("tags");
                    tag.clear();
                    Splitter.on(",").splitToList(tagStore.displayName2MetadataName(article.getTags())).forEach(tagMetaName->{
                       // 更新 akd 信息中的 tag
                       tag.add(tagMetaName);
                    });
                }
                if( !StringUtil.isEmpty(article.getCategories()) ) {
                    Splitter.on(",").trimResults().omitEmptyStrings().splitToList(article.getCategories())
                            .stream().forEach(cate->{
                                        categoriesStore.create(cate);
                                    }
                            );
                    JSONArray cates = entity.getAkd().getJSONObject("spec").getJSONArray("categories");
                    cates.clear();
                    Splitter.on(",").splitToList(categoriesStore.displayName2MetadataName(article.getCategories())).forEach(cateMetaName->{
                        // 更新 akd 信息中的 cate
                        cates.add(cateMetaName);
                    });
                }
                String putUri = StrFormatter.format(getPutUri(), entity.getMetadataName());
                // 更新 tag 和 categories
                put(putUri, HaloMarkdownBoot.server, ()->JSONObject.toJSONString(entity.getAkd()), rspData->{
                    return rspData;
                });
            }
        }
    }

    public Map<String,ArticleEntity> page(int page, int size, String search) {
        String listUri = StrFormatter.format(pageUri, page<=0?1:page, size<=0?2000:size, StringUtil.isEmpty(search)?"":search);
        cache = list(listUri, HaloMarkdownBoot.server, rspData->{
            Map<String, ArticleEntity> articleEntityMap = new HashMap<>();
            JSONArray items = JSONObject.parseObject(rspData).getJSONArray("items");
            items.stream().forEach(itemO->{
                JSONObject item = (JSONObject) itemO;
                JSONObject akd = item.getJSONObject("post");
                ArticleEntity entity = new ArticleEntity();
                entity.setAkd(akd);
                entity.setSlugId(akd.getJSONObject("spec").getString("slug"));
                entity.setTitle(akd.getJSONObject("spec").getString("title"));
                entity.setMetadataName(akd.getJSONObject("metadata").getString("name"));
                JSONArray cate = akd.getJSONObject("spec").getJSONArray("categories");
                if( cate!=null && !cate.isEmpty() ) {
                    entity.setCategories(cate.stream().map(v->v.toString()).collect(Collectors.joining(",")));
                }
                JSONArray tag = akd.getJSONObject("spec").getJSONArray("tags");
                if( tag!=null && !tag.isEmpty() ) {
                    entity.setTags(tag.stream().map(v->v.toString()).collect(Collectors.joining(",")));
                }
                articleEntityMap.put(entity.getTitle(), entity);
            });
            return articleEntityMap;
        });
        return cache;
    }
    public ArticleStore() {
        tagStore.list(0,0,"");
        categoriesStore.list();
    }

    public static void main(String[] args) {
        ArticleStore store = new ArticleStore();
//        String markdown = "# Hello, CommonMark!\n" +
//                "This is a paragraph with **bold** text and _italic_ text.\n" +
//                "Here is a list:\n" +
//                "- Item 1\n" +
//                "- Item 2\n" +
//                "- Item 3\n";
//        ArticleEntity entity = new ArticleEntity();
//        entity.setTitle("测试java代码创建");
//        entity.setSlugId("1234567890");
//        entity.setTags("新增一个tag,新增两个tag");
//        entity.setCategories("新增一个cate,新增两个cate");
//        entity.setMetadataName(UUID.randomUUID().toString());
//        entity.setContent(markdown);
//        store.createOrUpdate(entity);
        store.publish("iptables使用技巧系列文章");
    }
}
